package com.hb.trade.api.routine.controller.util;

import cn.hutool.core.io.resource.ClassPathResource;
import com.alibaba.fastjson.JSON;
import com.google.code.kaptcha.Producer;
import com.hb.core.pojo.center.au.dto.ForgetPasswordDTO;
import com.hb.core.pojo.center.au.dto.SliderImageCaptchaDTO;
import com.hb.core.pojo.center.au.dto.VerifyCodeDTO;
import com.hb.core.pojo.center.au.entity.User;
import com.hb.core.pojo.constant.Captcha;
import com.hb.core.pojo.constant.CaptchaConstant;
import com.hb.trade.api.routine.util.Base64Utils;
import com.hb.trade.api.routine.util.ImageConvertUtil;
import com.hb.trade.api.routine.util.PuzzleCaptchaUtile;
import com.hb.trade.client.center.UserClient;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import com.hb.core.pojo.constant.Constants;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.io.ResourceUtils;
import org.fzzn.core.cache.redis.StringRedisService;
import org.fzzn.core.model.enums.MsgEnum;
import org.fzzn.core.model.msg.Message;
import org.fzzn.core.model.msg.ResponseDto;
import org.fzzn.core.third.sms.service.SmsService;
import org.fzzn.core.util.MsgUtil;
import org.fzzn.core.util.ResultUtil;
import org.fzzn.core.web.anno.Version;

import javax.annotation.Resource;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
import cn.hutool.core.util.NumberUtil;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.awt.*;
import java.util.HashMap;
import java.util.Map;


@RestController
@Slf4j
@Version(1.0)
@Api(tags = {"第三方消息接口"})
@RequestMapping("/{version}")
public class ApiSmsController {

    @Resource(name = "captchaProducer")
    private Producer captchaProducer;

    protected final SmsService smsService;
    protected final StringRedisService redisService;
    protected final UserClient userClient;

    public ApiSmsController(SmsService smsService,
                            StringRedisService redisService,
                            UserClient userClient) {
        this.smsService = smsService;
        this.redisService = redisService;
        this.userClient = userClient;
    }


    /**
     * 发送验证码
     *
     * @param verifyCodeDTO
     * @return org.fzzn.core.model.msg.ResponseDto
     * @author tian
     * @date 2022-2-23 18:31
     */
    @ApiOperation(value = "发送验证码", notes = "发送验证码")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "phone", value = "手机号", dataTypeClass = Integer.class),
            @ApiImplicitParam(name = "uuid", value = "图片验证码uuid", dataTypeClass = String.class),
            @ApiImplicitParam(name = "code", value = "图片验证码", dataTypeClass = String.class)
    })
    @PostMapping("/sms/push")
    public ResponseDto push(@RequestBody VerifyCodeDTO verifyCodeDTO) {
        String phone = verifyCodeDTO.getPhone();
        String uuid = verifyCodeDTO.getUuid();
        String code = verifyCodeDTO.getCode();

        if (StringUtils.isEmpty(phone) || StringUtils.isEmpty(uuid) || StringUtils.isEmpty(code)) {
            return ResultUtil.fail(MsgEnum.INCORRECT_PARAM);
        }
        // 先判断图片验证码是否正确
        String verifyCodeKey = Constants.CAPTCHA_CODE_KEY + uuid;
        String codeByRedis = redisService.get(verifyCodeKey);

        // 判断验证码是否过期
        if (StringUtils.isEmpty(codeByRedis)) {
            return ResultUtil.fail(MsgEnum.VALID_CODE_DEPRECATED);
        }
        // 判断验证码是否正确
        if (!codeByRedis.equals(code)) {
            return ResultUtil.fail(MsgEnum.WRONG_VALID_CODE);
        }

        // 发送的验证码
        Integer phoneCode = (int) ((Math.random() * 9 + 1) * 100000);
        boolean captcha = smsService.sendCaptcha(phone, phoneCode.toString());
        // 将验证码放到缓存里面
        if (captcha) {
            // 5分钟有效期
            String verifyKey = Constants.PHONE_CAPTCHA_CODE_KEY + phone;
            redisService.set(verifyKey, phoneCode.toString(), Constants.CAPTCHA_EXPIRATION, TimeUnit.MINUTES);
            log.info(phone + "：短信验证码---------" + phoneCode);
            return ResultUtil.success("短信发送成功");
        }
        return ResultUtil.fail(MsgEnum.FAILURE);
    }


    /**
     * 获取图片验证码
     *
     * @return org.fzzn.core.model.msg.ResponseDto
     * @author tian
     * @date 2022-2-24 10:44
     */
    @ApiOperation(value = "获取图片验证码", notes = "获取图片验证码")
    @GetMapping("/sms/captchaImage")
    public ResponseDto captchaImage() {
        // 保存验证码信息
        String uuid = UUID.randomUUID().toString().replace("-", "").toLowerCase();
        String verifyKey = Constants.CAPTCHA_CODE_KEY + uuid;


        // 生成验证码
        String capStr = captchaProducer.createText();
        BufferedImage image = captchaProducer.createImage(capStr);

        redisService.set(verifyKey, capStr, Constants.CAPTCHA_EXPIRATION, TimeUnit.MINUTES);

        // 转换流信息写出
        ByteArrayOutputStream os = new ByteArrayOutputStream();
        try {
            ImageIO.write(image, "jpg", os);
        } catch (IOException e) {
            return ResultUtil.fail(MsgEnum.FAILURE);
        }
        VerifyCodeDTO verifyCodeDTO = new VerifyCodeDTO();
        verifyCodeDTO.setUuid(uuid);
        // 自带的Base64转出来不能展示图片
        verifyCodeDTO.setImg(Base64Utils.encode(os.toByteArray()));

        return ResultUtil.msg(MsgUtil.success(verifyCodeDTO));
    }


    @ApiOperation("获取验证码")
    @GetMapping(value = "/sms/getCaptchaSliderImage")
    public ResponseDto captcha() {
        // 保存验证码信息
        String uuid = UUID.randomUUID().toString().replace("-", "").toLowerCase();
        String verifyKey = Constants.CAPTCHA_CODE_KEY + uuid;

        // 读图--生成大图和缺口图
        ClassPathResource classPathResource = new ClassPathResource("template/ImageCaptcha.png");
        PuzzleCaptchaUtile puzzleCaptcha = new PuzzleCaptchaUtile(classPathResource);
        puzzleCaptcha.setImageQuality(Image.SCALE_AREA_AVERAGING);
        puzzleCaptcha.run();

        Map<String, Object> cacheMap = new HashMap<>();
        Captcha captchaVo = new Captcha();
        captchaVo.setSliceImg(ImageConvertUtil.toDataUri(puzzleCaptcha.getArtwork(), "png"));
        captchaVo.setBgImg(ImageConvertUtil.toDataUri(puzzleCaptcha.getVacancy(), "png"));
        captchaVo.setToken(verifyKey);

        // 偏移量
        cacheMap.put("x", puzzleCaptcha.getX());
        cacheMap.put("time", System.currentTimeMillis());
        cacheMap.put("width", puzzleCaptcha.getWidth());
        redisService.set(verifyKey, cacheMap.toString(), Constants.CAPTCHA_EXPIRATION, TimeUnit.MINUTES);
        return ResultUtil.msg(MsgUtil.success(captchaVo));
    }

    @ApiOperation("发送验证码")
    @PostMapping(value = "/sms/verify")
    public ResponseDto verify(@RequestBody SliderImageCaptchaDTO sliderImageCaptchaDTO) {
//        Integer X_OFFSET = 8;
//
//        Integer SPEED = 500;
        String phone = sliderImageCaptchaDTO.getPhone();
//        String token = sliderImageCaptchaDTO.getToken();
//        Integer vx = sliderImageCaptchaDTO.getX();
//        Integer width = sliderImageCaptchaDTO.getWidth();
//
//        if (width == null || vx == null ||token == null || phone == null){
//            return ResultUtil.fail(MsgEnum.INCORRECT_PARAM);
//        }
//
//        //缓存
//        String cacheMap = redisService.get(token);
//        if (cacheMap == null) {
//            return ResultUtil.fail("验证码已过期");
//        }
//        cacheMap = cacheMap.replace("=",":");
//        HashMap jsonObject = JSON.parseObject(cacheMap, HashMap.class);
//        Integer x = Integer.valueOf(jsonObject.get("x").toString());
//        Integer realWidth = Integer.valueOf(jsonObject.get("width").toString());
//        Long time = Long.valueOf(jsonObject.get("time").toString());
//        // 验证速度
//        long s = System.currentTimeMillis() - time;
//
//        // 查看前端的缩放比例
//        double ratio = NumberUtil.div(realWidth, width).doubleValue();
//
//        if (Math.abs(x - (vx * ratio)) > X_OFFSET * ratio || s < SPEED) {
//            return ResultUtil.fail("验证失败");
//        }

        // 发送的验证码
        Integer phoneCode = (int) ((Math.random() * 9 + 1) * 100000);
        try {
            boolean captcha = smsService.sendCaptcha(phone, phoneCode.toString());
            // 将验证码放到缓存里面
            if (captcha) {
                // 15分钟有效期
                String verifyKey = Constants.PHONE_CAPTCHA_CODE_KEY + phone;
                redisService.set(verifyKey, phoneCode.toString(), Constants.CAPTCHA_EXPIRATION, TimeUnit.MINUTES);
                log.info(phone + "：短信验证码---------" + phoneCode);
                return ResultUtil.success("短信发送成功");
            }
        }catch (Exception exception){
            log.debug(""+exception);
            return ResultUtil.fail("今日短信以超限制！");
        }


        return ResultUtil.fail(MsgEnum.FAILURE);
    }

    @ApiOperation("验证手机号和企业是否匹配")
    @PostMapping(value = "/sms/checkPhoneAndOrgName")
    public ResponseDto checkPhoneAndOrgName(@RequestBody ForgetPasswordDTO forgetPasswordDTO){
        Message<User> result = userClient.getUserByPhoneAndOrgName(forgetPasswordDTO);
        return ResultUtil.msg(result);
    }

}
